#ifndef __H_VS_SKIN_MODEL__
#define __H_VS_SKIN_MODEL__

#include "const_define.fx"
#include "struct_define.fx"
#include "light_calc.fx"
#include "fog_calc.fx"

struct SKIN_RESULT
{
	float3 position;
	float3 normal;    
};

// do the skin calculate.
SKIN_RESULT CalcSkin(float3 position, float3 normal, float4 index, float4 weight)
{
	SKIN_RESULT result;
	float4 inPos = float4(position, 1.0f);
	float i = index.x;
	float w = weight.x;

	result.position = mul(inPos, MAT_BONE_PALETTE[i]) * w;
	result.normal = mul(normal, (float3x3)MAT_BONE_PALETTE[i]) * w;

	if (weight.y > 0.0f)
	{
		i = index.y;
		w = weight.y;

		result.position += mul(inPos, MAT_BONE_PALETTE[i]) * w;
		result.normal += mul(normal, (float3x3)MAT_BONE_PALETTE[i]) * w;

		if(weight.z > 0.0f)
		{
			i = index.z;
			w = weight.z;

			result.position += mul(inPos, MAT_BONE_PALETTE[i]) * w;

			if(weight.w > 0.0f)
			{
				i = index.w;
				w = weight.w;

				result.position += mul(inPos, MAT_BONE_PALETTE[i]) * w;
			}
		}
	}

	return result;
}


// do the skin calculate.
SKIN_RESULT CalcSkin(float3 position, float4 index, float4 weight)
{
	SKIN_RESULT result;
	float4 inPos = float4(position, 1.0f);
	float i = index.x;
	float w = weight.x;

	result.position = mul(inPos, MAT_BONE_PALETTE[i]) * w;

	if (weight.y > 0.0f)
	{
		i = index.y;
		w = weight.y;

		result.position += mul(inPos, MAT_BONE_PALETTE[i]) * w;

		if(weight.z > 0.0f)
		{
			i = index.z;
			w = weight.z;

			result.position += mul(inPos, MAT_BONE_PALETTE[i]) * w;

			if(weight.w > 0.0f)
			{
				i = index.w;
				w = weight.w;

				result.position += mul(inPos, MAT_BONE_PALETTE[i]) * w;
			}
		}
	}

	return result;
}

// all texture color.
VSO VS_SKIN(VSI_SKIN IN)
{
	VSO OUT;
	SKIN_RESULT skinResult = CalcSkin(IN.position, IN.normal, IN.index, IN.weight);
	OUT.position = mul(float4(skinResult.position, 1.0f), MAT_WORLD_VIEW_PROJ);
	OUT.color = float4(1.0f, 1.0f, 1.0f, 1.0f);
	OUT.texCoord = IN.texCoord;

	return OUT;    
}

// ambient + diffuse light
VSO VS_SKIN_AD(VSI_SKIN IN)
{
	VSO OUT;
	SKIN_RESULT skinResult = CalcSkin(IN.position, IN.normal, IN.index, IN.weight);
	float3 normal = mul(skinResult.normal, (float3x3)MAT_WORLD);
	OUT.position = mul(float4(skinResult.position, 1.0f), MAT_WORLD_VIEW_PROJ);
	OUT.color = ambientLight + CalcDiffuse(lightDirection, normal, diffuseLight);
	OUT.texCoord = IN.texCoord;
	return OUT;
}

// ambient + diffuse + specular light.
VSO VS_SKIN_ADS(VSI_SKIN IN)
{
	VSO OUT;
	SKIN_RESULT skinResult = CalcSkin(IN.position, IN.normal, IN.index, IN.weight);
	float3 normal = mul(skinResult.normal, (float3x3)MAT_WORLD);
	OUT.position = mul(float4(skinResult.position, 1.0f), MAT_WORLD_VIEW_PROJ);    
	float4 diffuse = CalcDiffuse(lightDirection, normal, diffuseLight);
	float4 specular = CalcSpecular(skinResult.position, normal, specularLight, SHININESS);
	OUT.color = ambientLight + diffuse  + specular;
	OUT.texCoord = IN.texCoord;
	return OUT;
}

//-----------------------------------------------------------------------------

// all texture color.
VSO_FOG VS_SKIN_FOG(VSI_SKIN IN)
{
	VSO_FOG OUT;
	SKIN_RESULT skinResult = CalcSkin(IN.position, IN.index, IN.weight);
	OUT.position = mul(float4(skinResult.position, 1.0f), MAT_WORLD_VIEW_PROJ);
	OUT.color = float4(1.0f, 1.0f, 1.0f, 1.0f);
	OUT.texCoord = IN.texCoord;
	OUT.fog = calc_normal_fog(IN.position);
	return OUT;
}


// ambient + diffuse light
VSO_FOG VS_SKIN_AD_FOG(VSI_SKIN IN)
{
	VSO_FOG OUT;
	SKIN_RESULT skinResult = CalcSkin(IN.position, IN.normal, IN.index, IN.weight);
	float3 normal = mul(skinResult.normal, (float3x3)MAT_WORLD);
	OUT.position = mul(float4(skinResult.position, 1.0f), MAT_WORLD_VIEW_PROJ);
	OUT.color = ambientLight + CalcDiffuse(lightDirection, normal, diffuseLight);
	OUT.texCoord = IN.texCoord;
	OUT.fog = calc_normal_fog(IN.position);
	return OUT;
}

// ambient + diffuse + specular light.
VSO_FOG VS_SKIN_ADS_FOG(VSI_SKIN IN)
{
	VSO_FOG OUT;
	SKIN_RESULT skinResult = CalcSkin(IN.position, IN.normal, IN.index, IN.weight);
	float3 normal = mul(skinResult.normal, (float3x3)MAT_WORLD);
	OUT.position = mul(float4(skinResult.position, 1.0f), MAT_WORLD_VIEW_PROJ);    
	float4 diffuse = CalcDiffuse(lightDirection, normal, diffuseLight);
	float4 specular = CalcSpecular(skinResult.position, normal, specularLight, SHININESS);
	OUT.color = ambientLight + diffuse  + specular;
	OUT.texCoord = IN.texCoord;
	OUT.fog = calc_normal_fog(IN.position);
	return OUT;
}

#endif // __H_VS_SKIN_MODEL__
